<template>
    <el-card class="panel-index" ref="body1">
        <div :class="{isFull,'panel-container':true}" ref="container" style="width: 100%;height: 100%">
            <ToolBar ref="toolBar"
                     @onViewChange="onToolViewChange"
                     @onAddPanel="onAddPanel"
                     @onAddComponent="onAddComponent"
                     @onSave="onSave"
                    @onPreview="onPreview"/>
            <div style="display: flex;position: relative;height: 100%">
                <div style="flex: 1;width: 0;display: flex">
                    <div class="wrapper" ref="wrapper">
                        <SketchRule
                            :lang="lang"
                            :thick="thick"
                            :scale="scale"
                            :width="rulerWidth"
                            :height="rulerHeight"
                            :startX="startX"
                            :startY="startY"
                            :shadow="shadow"
                            :horLineArr="lines.h"
                            :verLineArr="lines.v"
                            :cornerActive="false"
                            @handleLine="handleLine"
                            @onCornerClick="handleCornerClick"
                        >
                        </SketchRule>
                        <RightKeyMenu ref="rightKeyMenu"
                                      v-show="activeIndex !== -1"
                                      :visible="isShowMenu"
                                      :com="this.activeCom"
                                      @onClick="handleMenuClick"/>
                        <div
                            ref='screensRef'
                            id="screens"
                            @wheel="handleWheel"
                            @scroll="handleScroll"
                        >
                            <div ref="containerRef" class="screen-container">
                                <BackgroundComponent ref="background" :data-json="{}" @clickBg="onDeactivated">
                                    <div class="object-box">
                                        <template v-for="(item,index) in comList">
                                            <vue-draggable-resizable
                                                @click.native.stop.prevent="() =>{}"
                                                @contextmenu.native.prevent="e => handleRightKey(e,index)"
                                                :class="{'my-com':true,active:index === activeIndex}"
                                                :key="item.key"
                                                :w=item.location.w
                                                :h=item.location.h
                                                :x=item.location.x
                                                :y=item.location.y
                                                :scroll-sensitivity="150"
                                                :force-fallback="false"
                                                :min-width="10"
                                                :min-height="10"
                                                :snapTolerance="10"
                                                :draggable="true"
                                                :resizable="true"
                                                :snap="false"
                                                :parent="true"
                                                :active="activeIndex === index || groupActiveList.includes(index)"
                                                :prevent-deactivation="true"
                                                @click.native.prevent.stop="(e) =>handleComClick(index)"
                                                @dragging="(x, y) => onDrag(x, y)"
                                                @resizing="(x, y,w,h) => onResize(x, y,w,h)"
                                                @resizestop="onResizeStop"
                                                @activated="onActivated(index)">
                                                <div class="drag-info" v-if="index === activeIndex">
                                                <span
                                                    class="drag-info-xy">{{item.location.x}},{{item.location.y}}</span>
                                                    <span class="drag-info-width">{{item.location.w}}</span>
                                                    <span class="drag-info-height">{{item.location.h}}</span>
                                                    <p class="drag-info-line-x"></p>
                                                    <p class="drag-info-line-y"></p>
                                                </div>
                                                <div v-if="item.objType!==3"
                                                     class="group-child-box">
                                                    <component :is="item.component" :dataJson="item.dataJson"
                                                               :ref="'com-'+item.key"/>

                                                </div>
                                                <div v-else class="group-child-box"  v-for="groupc in item.children"
                                                     :key="groupc.key"
                                                     :style="`position:absolute;top:${groupc.transform.y}px;left:${groupc.transform.x}px;width:${groupc.transform.w}px;height:${groupc.transform.h}px`">
                                                    <component :is="groupc.component" :dataJson="groupc.dataJson"
                                                               :ref="'com-'+groupc.key" />
                                                </div>
                                            </vue-draggable-resizable>
                                        </template>
                                    </div>
                                </BackgroundComponent>
                            </div>
                        </div>
                    </div>
                    <OperateBar ref="operateBar"
                                :list="comList"
                                @click.stop="() => {return false}"
                                @onActivated="onActivated"
                                @onSort="onSort"
                                @onFormChange="onFormChange"
                                @onRightKeyClick="handleRightKey"
                                @onOperateViewChange="init"/>
                </div>
            </div>
        </div>

    </el-card>

</template>

<script>
    import SketchRule from "vue-sketch-ruler";
    import VueDraggableResizable from 'vue-draggable-resizable-gorkys'
    import 'vue-draggable-resizable-gorkys/dist/VueDraggableResizable.css'
    import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
    import ToolBar from './ToolBar'
    import OperateBar from './OperateBar'
    import allComponent from './components/index'
    import BackgroundComponent from "./components/BackgroundComponent";
    import {MessageBox,Message } from "element-ui";
    import RightKeyMenu from "./RightKeyMenu";

    export default {
        name: "DataScreen",
        components: {RightKeyMenu, VueDraggableResizable, SketchRule, ToolBar, OperateBar,BackgroundComponent},
        data() {
            return {
                allComponent,
                id:'',
                isFull: false,
                rectWidth: 1000,
                rectHeight: 500,
                rulerWidth: 980,
                rulerHeight: 480,
                scale: 1,
                startX: 0,
                startY: 0,
                lines: {
                    h: [],
                    v: []
                },
                thick: 20,
                lang: "zh-CN", // 中英文
                isShowRuler: true, // 显示标尺
                isShowReferLine: true, // 显示参考线
                comList: [
                    // {
                    //     key: '1',
                    //     objType: 1, // 对象类型 => 图表对象/装饰对象
                    //     name: '测试组件1',
                    //     componentName: 'TestComponent',
                    //     location: { // 位置数据
                    //         x: 0, // 左上角x坐标
                    //         y: 0,// 左上角y坐标
                    //         w: 100, // 宽度
                    //         h: 100, // 高度
                    //     },
                    //     dataJson: {},
                    //     children:[]
                    // },
                ],
                activeIndex: -1,
                groupActiveList:[],
                isShowMenu: false,
                isCtrlKey:false,
            }
        },
        watch: {
            scale(v){
                this.$refs.background.$el.style.transform = `scale(${v})`;
            }
        },
        computed: {
            shadow() {
                return {
                    x: 0,
                    y: 0,
                    width: this.rectWidth,
                    height: this.rectHeight
                }
            },
            activeCom() {
                if (this.activeIndex === -1) return null
                return this.comList[this.activeIndex]
            },
            activeRef() {
                if (this.activeIndex === -1) return null
                const ref = `com-${this.comList[this.activeIndex].key}`
                const comRef = this.$refs[ref]
                if (comRef && Array.isArray(comRef) && comRef.length !== 0) {
                    return this.$refs[ref][0]
                }
                return null
            }
        },
        mounted() {
            this.id = this.$route.query.boardId
            this.init()
            const data = localStorage.getItem('screen'+this.id)
            if(data){
                const temp = JSON.parse(data)
                if(temp.components){
                    this.comList = temp.components
                    this.loadComponent(this.comList)
                }
                if(temp.background){
                    this.$refs.background.updateData(temp.background)
                }
            }
            document.onkeydown = e => this.handleKeyDown(e)
            document.onkeyup = e => this.handleKeyUp(e)
        },
        destroyed() {
            // window.removeEventListener('keypress',this.handleKeyDown)
            // window.removeEventListener('keyup',this.handleKeyUp)
        },
        methods: {
            init() {
                const containerRect = this.$refs.container.getBoundingClientRect()
                const operateBarRect = this.$refs.operateBar.getBoundingClientRect()
                this.rectWidth = containerRect.width - operateBarRect.width
                this.rectHeight = containerRect.height - 50
                this.$refs.wrapper.style.width = this.rectWidth + 'px'
                this.$refs.wrapper.style.height = this.rectHeight + 'px'
                this.rulerHeight = this.rectHeight - this.thick
                this.rulerWidth = this.rectWidth - this.thick
                this.$nextTick(() => {
                    window.dispatchEvent(new Event('resize'))
                })
            },
            loadComponent(list){
                return list.map(com => {
                    if(com.objType !== 3){
                        com.component = this.allComponent[com.componentName]
                    }else{
                        com.children = this.loadComponent(com.children)
                    }
                    return com
                })
            },
            handleKeyDown(e){
                console.log('按下')
                if(e.ctrlKey){
                    this.isCtrlKey = true
                }
            },
            handleKeyUp(e){
                console.log('放开')
                if(e.ctrlKey){
                    this.isCtrlKey = false
                }
            },
            // 图层排序
            onSort(orderList = []) {
                if (orderList && orderList.length !== 0) {
                    this.comList.sort((a, b) => {
                        return orderList.indexOf(a.key) - orderList.indexOf(b.key)
                    })
                }
            },
            // 工具栏视图变化回调
            onToolViewChange(data = {}) {
                Object.keys(data).forEach(item => {
                    this[item] = data[item]
                })
                this.$nextTick(() => {
                    this.init()
                })
            },
            // 工具栏添加仪表组件回调
            onAddPanel(data) {
                this.comList.push({
                    key: new Date().getTime(),
                    objType: 1, // 对象类型 => 图表对象/装饰对象
                    name: data.titleId,
                    componentName: 'PanelComponent',
                    component: this.allComponent['PanelComponent'],
                    location: { // 位置数据
                        x: 0, // 左上角x坐标
                        y: 0,// 左上角y坐标
                        w: data.width, // 宽度
                        h: data.length, // 高度
                    },
                    dataJson: {
                        ...data
                    },
                })
                this.$forceUpdate()
            },
            // 添加组件
            onAddComponent(data){
                this.comList.push({
                    key: new Date().getTime(),
                    objType: 2, // 对象类型 => 图表对象/装饰对象
                    name: data.name,
                    componentName: data.componentName,
                    component: this.allComponent[data.componentName],
                    location: { // 位置数据
                        x: 0, // 左上角x坐标
                        y: 0,// 左上角y坐标
                        w: 200, // 宽度
                        h: 200, // 高度
                    },
                    dataJson: {},
                })
                this.$forceUpdate()
            },
            // 改变组件位置的方法
            onDrag(x, y) {
                const activeData = this.activeCom
                if (activeData) {
                    activeData.location.x = x
                    activeData.location.y = y
                    this.comList[this.activeIndex] = activeData
                }
            },
            onResizeStop(){
                let index = this.activeIndex;
                console.log('----------------------')
                this.activeRef.updateData(this.comList[index].dataJson)
            },
            // 尺寸改变
            onResize(x, y, w, h) {
                const _w = this.activeCom.location.w
                const _h = this.activeCom.location.h
                const activeData = this.activeCom
                activeData.location.w = Math.floor(w)
                activeData.location.h = Math.floor(h)
                if (activeData.objType === 1) {
                    activeData.dataJson.width = Math.floor(w)
                    activeData.dataJson.length = Math.floor(h)
                }else if(activeData.objType === 3){
                    // 组合缩放，需要同步缩放子组件
                    const ratioW = Number((w/_w).toFixed(3))
                    const ratioH = Number((h/_h).toFixed(3))
                    activeData.children.forEach(item => {
                        item.transform.w *=ratioW
                        item.transform.h *=ratioH
                        item.transform.x *=ratioW
                        item.transform.y *=ratioH
                        item.dataJson.width = item.transform.w
                        item.dataJson.length = item.transform.h
                    })
                }
                this.comList[this.activeIndex] = activeData
            },
            // 激活
            onActivated(index) {
                this.isShowMenu = false
                this.activeIndex = index
                this.$refs.operateBar.setActive(index)
                if (this.activeRef) {
                    this.activeRef.updateData(this.comList[index].dataJson)
                    const attrs = this.activeRef.interfaceAttrs
                    this.$refs.operateBar.setForm(attrs)
                }else{
                    this.$refs.operateBar.setForm()
                }
            },
            handleComClick(index){
                if(this.isCtrlKey){
                    const i = this.groupActiveList.findIndex(item => item === index)
                    if(i !== -1){
                        this.groupActiveList.splice(i,1)
                    }else{
                        this.groupActiveList.push(index)
                    }
                }
            },
            // 取消选中+点击背景
            onDeactivated() {
                this.activeIndex = -1
                this.$refs.operateBar.setActive(-1)
                this.isShowMenu = false
                this.isCtrlKey = false
                this.groupActiveList.length = 0
                const attrs = this.$refs.background.interfaceAttrs
                this.$refs.operateBar.setForm(attrs)
            },
            onPreview(){
                let host = location.host
                window.open('http://'+host+'/#/dataScreen-preview?id='+this.id,'_blank')
            },
            // 保存
            onSave() {
                const deleteComponent = (list) => {
                    return list.map(item => {
                        delete item.component
                        if(item.objType === 3 && item.children && item.children.length !==0){
                            item.children = deleteComponent(item.children)
                        }
                        return item
                    })
                }
                const test = JSON.parse(JSON.stringify(this.comList))
                const ddd = deleteComponent(test)
                const data = {
                    background:this.$refs.background.dynamicData, // 背景设置
                    components:ddd, // 其他组件设置
                }
                localStorage.setItem('screen'+this.id, JSON.stringify(data))
                Message('保存成功')
                console.log(this.comList)
            },
            handleLine(lines) {
                this.lines = lines;
            },
            handleCornerClick() {
                return;
            },
            handleScroll() {
                const screensRect = document
                    .querySelector("#screens")
                    .getBoundingClientRect();
                const canvasRect = this.$refs.background.$el.getBoundingClientRect()

                // 标尺开始的刻度
                const startX = (screensRect.left + this.thick - canvasRect.left) / this.scale;
                const startY = (screensRect.top + this.thick - canvasRect.top) / this.scale;

                this.startX = startX;
                this.startY = startY;
            },
            // 控制缩放值
            handleWheel(e) {
                if (e.ctrlKey || e.metaKey) {
                    e.preventDefault();
                    const nextScale = parseFloat(
                        Math.max(0.05, this.scale - e.deltaY / 5000).toFixed(2)
                    );
                    if (nextScale <= 1) {
                        this.scale = nextScale;
                        this.$refs.toolBar.setParams({scale: nextScale * 100})
                    }
                }
                this.$nextTick(() => {
                    this.handleScroll();
                });
            },
            // 右键点击，弹出菜单
            handleRightKey(e, index) {
                this.activeIndex = index
                const offsetX = this.isFull ? 0 : 180
                const offsetY = this.isFull ? 51 : 171
                this.$refs.rightKeyMenu.updateLocation(e.pageX - offsetX, e.pageY - offsetY)
                setTimeout(() => {
                    this.isShowMenu = true
                })
            },
            // 点击菜单
            handleMenuClick(type) {
                if (type === 'remove') {
                    MessageBox.confirm('确认删除该组件吗？', '温馨提示').then(() => {
                        this.comList.splice(this.activeIndex, 1)
                        this.isShowMenu = false
                    })
                } else if (type === 'copy') {
                    const temp = JSON.parse(JSON.stringify(this.activeCom))
                    delete temp.component
                    const newCom = Object.assign(temp, {
                        key: new Date().getTime(),
                        component: this.allComponent[temp.componentName]
                    })
                    newCom.location.x += 50
                    newCom.location.y += 50
                    this.comList.push(newCom)
                } else if (type === 'first') {
                    const temp = this.comList.splice(this.activeIndex, 1)
                    this.comList = [...this.comList, temp[0]]
                } else if (type === 'last') {
                    const temp = this.comList.splice(this.activeIndex, 1)
                    this.comList = [temp[0], ...this.comList]
                }else if(type === 'group'){
                    this.group()
                }else if(type === 'groupCancel'){
                    this.groupCancel()
                }
            },
            // 组件对应表单的值修改回调
            onFormChange(form) {
                if(this.activeIndex>-1){ // 设置组件参数的表单
                    this.activeCom.dataJson = form
                    const curCom = `com-${this.activeCom.key}`
                    this.activeRef.updateData(form)
                }else{// 设置背景参数的表单
                    this.$refs.background.updateData(form)
                }
            },
            // 组合
            group(){
                if(this.groupActiveList.length<2) return
                // 被组合的组件
                const tempList = this.comList.filter((item,index) => this.groupActiveList.includes(index));
                if(tempList.findIndex(item=> item.objType === 3) >-1) {
                    Message('被组合的组件不能再次和参与组合')
                    return
                }
                // 计算组合后父组件的坐标和尺寸
                const x = Math.min(...tempList.map(item => item.location.x))
                const y = Math.min(...tempList.map(item => item.location.y))
                const w = Math.max(...tempList.map(item => (item.location.x+item.location.w))) - x
                const h = Math.max(...tempList.map(item => (item.location.y+item.location.h))) - y

                const groupCom = {
                    key:new Date().getTime(),
                    objType: 3, // 对象类型 => 图表对象/装饰对象/组合对象
                    name: '组合'+(this.comList.filter(item => item.objType === 3).length +1),
                    componentName: 'Group',
                    location: { x,y,w,h,},
                    children:tempList.map(item => {
                        const {x:ix,y:iy,w:iw,h:ih} = item.location
                        // 组合的子组件需要加一个变换信息，记录相对于父组件的相对位置
                        item.transform = {
                            x:ix - x,// 偏移量x
                            y:iy - y,
                            w:iw,// 组合后子组件尺寸不变，后续父变化，子需要跟随变化
                            h:ih
                        }
                        return item
                    })
                }
                // 在队列中剔除掉被组合的组件
                this.comList = this.comList.filter((item,index) => !this.groupActiveList.includes(index));
                // 在队列中加入新的组合
                this.comList.push(groupCom)
                // 取消组合中状态
                this.isCtrlKey = false
                // 菜单消失
                this.isShowMenu = false
            },
            groupCancel(){
                const {location,children = []} = this.activeCom;
                this.comList.splice(this.activeIndex,1)
                this.onDeactivated()
                children.forEach(item => {
                    const {x,y,w,h} = item.transform
                    item.location = {
                        w:Number(w.toFixed(0)),
                        h:Number(h.toFixed(0)),
                        x:location.x+x,
                        y:location.y+y,
                    }
                    delete item.transform
                    this.comList.push(item)
                })
            }

        },
    }
</script>

<style scoped lang="stylus">
    .panel-index /deep/ {
        height 100%

        .el-card__body {
            height 100% !important
            padding 0 !important
        }

        .v-header {
            margin-bottom 0 !important

            p {
                margin 0 !important
            }
        }
    }

    .panel-index {
        .panel-container {
            transition all 0.3s

            &.isFull {
                position fixed
                top 0
                left 0
                width 100%
                height 100%
                background-color white
            }
        }
    }

    .my-com {
        border none

        &.active {
            transition all 0.3
            background-color rgba(255, 255, 255, 0.5)

            &.dragging {
                background-color rgba(255, 255, 255, 0.2)
                opacity 0.6
            }
        }

        &:hover {
            background-color rgba(255, 255, 255, 0.5)
            cursor all-scroll
        }
        .group-child-box{
            display: flex;
            width: 100%;
            height: 100%;
            justify-content: center;
            align-items: center
        }
    }

    .wrapper {
        background-color: #ffffff;
        position relative
        top: 0px;
        left: 0px;
        width: 1000px;
        height: 500px;
        border: 1px solid #DADADC;
        flex 1
    }

    #screens {
        position: absolute;
        width: 100%;
        height: 100%;
        overflow: auto;
    }

    .screen-container {
        position: absolute;
        width: 5000px;
        height: 3000px;
        background: linear-gradient(-90deg, rgba(0, 0, 0, 0.1) 1px, transparent 1px) 0% 0% / 20px 20px, linear-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 1px) 0% 0% / 20px 20px;
    }
    .object-box {
        position absolute
        top 0
        left 0
        width 100%
        height 100%
        z-index 1000
    }

    .drag-info {
        color red
        position absolute
        height 100%
        width 100%

        &-xy {
            position absolute
            top 0
            left 0
            font-size 13px
            transform translate(-100%, -100%)
            transform-origin: 100% 100%
            padding 4px
        }

        &-line-x {
            position absolute
            width: 3000px;
            height: 0;
            margin-bottom: -4px;
            border-bottom: 1px dotted rgb(235, 86, 72);
            top 0
            left -3000px
            opacity 0.8
        }

        &-line-y {
            position absolute
            width: 0;
            height: 2000px;
            border-right: 1px dotted rgb(235, 86, 72)
            top: -2000px;
            left: -1px;
            opacity 0.8
        }

        &-width {
            position: absolute;
            top: -20px;
            left: 75%;
            font-size 13px
        }

        &-height {
            position: absolute;
            top: 25%;
            right: 0;
            transform: translate(100%, 0);
            font-size 13px
        }
    }
</style>
